﻿using System;
using System.ComponentModel;
using System.IO;
using System.Security.Cryptography;
using System.Web;

using AlpineSoft;
using System.Text;
using QuickDev.Common.Audit;

namespace QuickDev.Licensing
{
    public class AppLicenseProvider : System.ComponentModel.LicenseProvider
    {
        #region Constants

        private const string LICENSE_PATH = "~/bin/{0}.lic";

        #endregion

        #region Methods

        #region Public

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="type"></param>
        /// <param name="instance"></param>
        /// <param name="allowExceptions"></param>
        /// <returns></returns>
        public override System.ComponentModel.License GetLicense( LicenseContext context , Type type , object instance , bool allowExceptions )
        {
            AppLicense license = null;
            if ( context != null )
            {
                LicenseUsageMode usageMode = context.UsageMode;
            }
            if ( license == null )
            {
                Stream stream = null;
                StreamReader reader = null;
                try
                {
                    string path = HttpContext.Current.Server.MapPath( string.Format( "~/bin/{0}.lic" , type.FullName ) );
                    if ( File.Exists( path ) )
                    {
                        stream = new FileStream( path , FileMode.Open , FileAccess.Read , FileShare.Read );
                        reader = new StreamReader( stream );
                        string key = reader.ReadToEnd();
                        if ( this.IsKeyValid( key , type , instance ) )
                        {
                            license = new AppLicense( this , key );
                        }
                    }
                }
                finally
                {
                    if ( stream != null )
                    {
                        stream.Close();
                        stream.Dispose();
                    }
                    if ( reader != null )
                    {
                        reader.Close();
                        reader.Dispose();
                    }
                }
            }
            return license;
        }

        /// <summary>
        /// IsKeyValid
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="type">type</param>
        /// <param name="instance">instance</param>
        /// <returns></returns>
        protected virtual bool IsKeyValid( string key , Type type , object instance )
        {
            bool flag = false;

            if ( key != null )
            {
                if ( !( instance is ILicenseProvider ) )
                {
                    throw new InvalidOperationException( "Provider does not implement the ILicenseProvider interface." );
                }

                ILicenseProvider provider = instance as ILicenseProvider;

                EZRSA ezrsa = new EZRSA( 0x400 );//1024

                ezrsa.FromXmlString( provider.PublicKey );

                Serializer serializer = new Serializer();
                ILicense license = serializer.DeserializeObject( key , typeof( QuickDev.Licensing.License ).AssemblyQualifiedName ) as ILicense;
                if ( license == null )
                {
                    return flag;
                }

                //VerifyData
                flag = ezrsa.VerifyData( license.Signature , new SHA1CryptoServiceProvider() , Convert.FromBase64String( license.Key ) );
                Logger.Debug( "IS KEY VALID: " + flag.ToString() );

                Uri url = HttpContext.Current.Request.Url;
                Logger.Debug( "CURRENT URL HOST: " + url.Host );

                //Check Local host
                if ( url.IsLoopback )
                {
                    return flag;
                }

                //Check license Domain
                StringBuilder builder = new StringBuilder();
                if ( !url.Host.Contains( license.Domain ) )
                {
                    flag = false;
                    builder.AppendLine( "FAIL DOMAIN CHECK" );
                }

                //Check license ExpirationDate
                if ( DateTime.UtcNow > license.ExpirationDate )
                {
                    flag = false;
                    builder.AppendLine( "FAIL EXPIRATION DATE CHECK" );
                }

                //Check instance
                if ( ( instance.GetType() != type ) && !instance.GetType().IsSubclassOf( type ) )
                {
                    flag = false;
                    builder.AppendLine( "FAIL LICENSE / INSTANCE CHECK" );
                }

                //Check type
                if ( type.FullName != license.Type )
                {
                    flag = false;
                    builder.AppendLine( "FAIL LICENSE / TYPE CHECK" );
                }

                //Logger the verify result.
                builder.AppendFormat( "LICENSE DOMAIN: {0} IS IN CURRENT URL HOST: {1}" , license.Domain , url.Host );
                builder.AppendFormat( "LICENSE EXPIRATIONDATE: {0} IS GREATER THAN UTC DATETIME: {1}" , license.ExpirationDate , DateTime.UtcNow );
                builder.AppendFormat( "INSTANCE TYPE: {0} IS EQUAL TO TYPE: {1}" , instance.GetType().FullName , type.FullName );
                builder.AppendFormat( "INSTANCE IS SUBCLASS OF {0}: {1}" , license.Type , instance.GetType().IsSubclassOf( type ) );
                builder.AppendFormat( "LICENSE TYPE: {0} IS EQUAL TO TYPE FULLNAME: {1}" , license.Type , type.FullName );
                Logger.Debug( builder.ToString() );
            }

            return flag;
        }

        #endregion

        #endregion
    }
}

